#pragma once
#include <iostream>
#include <string>
#include <memory>
using namespace std;
const string CalSep = " ";

enum
{
    Success = 0,
    DivZero,
    ModZero,
    Unknown,

};

const string opers = "+-*/%^=";

namespace Calculator
{
    class Response
    {
    public:
        Response() {}
        Response(int result, int code = 0) : _result(result), _code(code) {}

        void Serialize(string *content)
        {
            *content = to_string(_result) + CalSep + to_string(_code);
        }

        void Deserialize(const string &content, bool *ok)
        {
            *ok = true;
            int pos = content.find(CalSep);
            if (pos == string::npos)
            {
                *ok = false;
                return;
            }

            _result = stoi(content.substr(0, pos));
            _code = stoi(content.substr(pos + CalSep.size()));
        }

        void Debug()
        {
            cout << _result << " : " << _code << endl;
        }

        int GetResult() { return _result; }
        int GetCode() { return _code; }

    private:
        int _result;
        int _code;
    };

    class Request
    {
    public:
        Request() {}
        Request(int data_x, int data_y, char oper) : _data_x(data_x), _data_y(data_y), _oper(oper) {}

        void Serialize(string *content)
        {
            *content = to_string(_data_x) + CalSep + _oper + CalSep + to_string(_data_y);
        }

        void Deserialize(const string &content, bool *ok)
        {
            *ok = true;
            int left = content.find(CalSep);
            if (left == string::npos)
            {
                *ok = false;
                return;
            }

            int right = content.rfind(CalSep);
            if (right == left)
            {
                *ok = false;
                return;
            }

            _data_x = stoi(content.substr(0, left));
            std::string oper = content.substr(left + CalSep.size(), right - (left + CalSep.size()));
            if (oper.size() != 1)
                *ok = false;
            _oper = oper[0];
            _data_y = stoi(content.substr(right + CalSep.size()));
        }

        shared_ptr<Calculator::Response> Result()
        {
            switch (_oper)
            {
            case '+':
                return make_shared<Calculator::Response>(_data_x + _data_y);
            case '-':
                return make_shared<Calculator::Response>(_data_x - _data_y);
            case '*':
                return make_shared<Calculator::Response>(_data_x * _data_y);
            case '/':
                if (_data_y == 0)
                    return make_shared<Calculator::Response>(0, DivZero);
                else
                    return make_shared<Calculator::Response>(_data_x / _data_y);
            case '%':
                if (_data_y == 0)
                    return make_shared<Calculator::Response>(0, ModZero);
                else
                    return make_shared<Calculator::Response>(_data_x % _data_y);
            default:
                return make_shared<Calculator::Response>(0, Unknown);
            }
        }

        void Debug()
        {
            cout << _data_x << " " << _oper << " " << _data_y << endl;
        }

        int GetX() { return _data_x; }
        int GetY() { return _data_y; }
        char GetOp() { return _oper; }

    private:
        int _data_x;
        int _data_y;
        char _oper;
    };
}